package com.lingjtx.common.thread.commom;

import com.lingjtx.common.core.ResponseCode;
import com.lingjtx.common.core.ResponseResult;
import com.lingjtx.common.core.exception.ParamCheckException;
import com.lingjtx.common.core.exception.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.reactive.resource.NoResourceFoundException;
import reactor.core.publisher.Mono;

import java.util.stream.Collectors;

/**
 * 全局异常处理类
 *
 * @author John Liu
 */
@RestControllerAdvice
public class NettyServerExceptionResolver {

    private static final Logger log = LoggerFactory.getLogger(NettyServerExceptionResolver.class);

    @ExceptionHandler(Exception.class)
    public Mono<ResponseResult<String>> globalException(Exception e) {
        log.error("全局异常信息：{}", e.getMessage(), e);

        // 业务异常交由 sentinel 记录
//        Tracer.trace(e);
        return Mono.just(ResponseResult.createByError());
    }

    @ExceptionHandler(NoResourceFoundException.class)
    public Mono<ResponseResult<String>> notFoundException(NoResourceFoundException e) {
        log.debug("请求路径 404 {}", e.getMessage());
        return Mono.just(ResponseResult.createByError(ResponseCode.RESOURCE_NOT_EXIST));
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Mono<ResponseResult<String>> paramCheckException(MethodArgumentNotValidException e) {
        log.warn("参数校验异常：{}", e.getMessage());
        return Mono.just(ResponseResult.createByError(String.format("参数校验错误: %s",
                e.getBindingResult()
                        .getFieldErrors()
                        .stream()
                        .map(FieldError::getDefaultMessage)
                        .collect(Collectors.joining(";")))));
    }

    /**
     * 处理业务校验过程中碰到的非法参数异常 该异常基本由{@link Assert}抛出
     *
     * @param e 参数校验异常
     * @return API返回结果对象包装后的错误输出结果
     * @see Assert#hasLength(String, String)
     * @see Assert#hasText(String, String)
     * @see Assert#isTrue(boolean, String)
     * @see Assert#isNull(Object, String)
     * @see Assert#notNull(Object, String)
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public Mono<ResponseResult<String>> paramException(IllegalArgumentException e) {
        log.warn("非法参数异常：{}", e.getMessage(), e);
        return Mono.just(ResponseResult.createByError("非法参数"));
    }

    @ExceptionHandler(ParamCheckException.class)
    public Mono<ResponseResult<String>> paramEmptyException() {
        log.warn("参数为空!!!");
        return Mono.just(ResponseResult.createByError(ResponseCode.PARAM_IS_NULL));
    }


    @ExceptionHandler(UnauthorizedException.class)
    public Mono<ResponseResult<String>> unauthorizedException(UnauthorizedException e) {
        log.error("API KEY 验证错误：{}", e.getMessage());
        return Mono.just(ResponseResult.createByError(e.getResponse() == null ?
                ResponseCode.UNAUTHORIZED.getCode() :
                e.getResponse().getCode(), e.getMessage()));
    }

    @ExceptionHandler(MultipartException.class)
    public Mono<ResponseResult<String>> multipartException(MultipartException e) {
        log.error("文件上传异常：{}", e.getMessage());
        return Mono.just(ResponseResult.createByError("上传文件失败：" + e.getMessage()));
    }
}
